﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using Utils;
using Utils.Wpf;

namespace Plugins.UserControls
{
	public class PresetSelectorVM<T> : ViewModelBase, IPresetSelector where T : ICopyable<T>, ICloneable<T>
	{
		#region Attributes

		private string _presetName;
		private Preset<T> _selectedPreset;
		
		private readonly T _settings;

		private readonly PresetsDataSource<T> _dataSource;

		#endregion
		
		#region Properties

		public ObservableCollection<Preset<T>> Presets { get; private set; }

		public Preset<T> SelectedPreset
		{
			get
			{
				return _selectedPreset;
			}
			set
			{
				if (_selectedPreset != value)
				{
					_selectedPreset = value;
					base.OnPropertyChanged("SelectedPreset");
					this.PresetName = value == null ? null : _selectedPreset.Name;
				}
			}
		}

		public string PresetName
		{
			get
			{
				return _presetName;
			}
			set
			{
				if (_presetName != value)
				{
					_presetName = value;
					base.OnPropertyChanged("PresetName");
				}
			}
		}

		public ICommand SaveCommand { get; private set; }
		public ICommand DeleteCommand { get; private set; }
		public ICommand LoadCommand { get; private set; }
		public ICommand RefreshPresetsCommand { get; private set; }

		#endregion

		#region Events

		internal event EventHandler<EventArgs> AfterLoad;

		#endregion

		#region Public Methods

		public PresetSelectorVM(string filename, T settings)
		{
			_settings = settings;

			_dataSource = new PresetsDataSource<T>(filename);

			this.Presets = new ObservableCollection<Preset<T>>();

			this.SaveCommand = new DelegateCommand(this.ExecuteSave,this.CanSave);
			this.DeleteCommand = new DelegateCommand(this.ExecuteDelete, this.CanDelete);
			this.LoadCommand = new DelegateCommand(this.ExecuteLoad, this.CanLoad);
			this.RefreshPresetsCommand = new DelegateCommand(this.ExecuteRefreshPresets, this.CanRefreshPresets);
		}

		protected virtual void OnAfterLoad()
		{
			if (this.AfterLoad != null)
			{
				this.AfterLoad(this, EventArgs.Empty);
			}
		}

		#endregion

		#region Private Methods

		private void ExecuteSave()
		{
			Preset<T> newPreset = new Preset<T>(_presetName, _settings.Clone());
			this.Presets.Add(newPreset);
			this.PresetName = null;
			this.SelectedPreset = newPreset;

			_dataSource.Save(this.Presets);
		}

		private bool CanSave()
		{
			return !string.IsNullOrEmpty(_presetName) && this.Presets.All(p => p.Name != _presetName);
		}

		private void ExecuteDelete()
		{
			this.Presets.Remove(_selectedPreset);

			_dataSource.Save(this.Presets);
		}

		private bool CanDelete()
		{
			return _selectedPreset != null;
		}

		private void ExecuteLoad()
		{
			_settings.Copy(_selectedPreset.Settings);
			this.OnAfterLoad();
		}

		private bool CanLoad()
		{
			return _selectedPreset != null;
		}

		private void ExecuteRefreshPresets()
		{
			this.Presets.Clear();

			foreach (Preset<T> preset in _dataSource.Load())
			{
				this.Presets.Add(preset);	
			}
		}

		private bool CanRefreshPresets()
		{
			return this.Presets.Count == 0;
		}

		#endregion
	}
}
